package com.content.management.controller;

import com.content.management.annotation.ResponseResult;
import com.content.management.common.WrapMapper;
import com.content.management.common.Wrapper;
import com.content.management.config.ResponseResultInterceptor;
import com.content.management.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author xinghu
 * @version 1.0
 * @date 2020/3/2 12:19 上午
 */
@Slf4j
@ControllerAdvice

public class ResponseHandlerController implements ResponseBodyAdvice<Object> {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public Object exception(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        List<ObjectError> allErrors = bindingResult.getAllErrors();
        return WrapMapper.illegalArgument().result(allErrors.stream().map(objectError -> {
            FieldError fieldError = (FieldError)objectError;
            return fieldError.getObjectName() + ":" + fieldError.getDefaultMessage();
        }).collect(Collectors.joining(";")));
    }

    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseBody
    public Object exception(IllegalArgumentException e) {
        log.error("ControllerAdvice", e);
        return WrapMapper.illegalArgument().message(e.getMessage());
    }

    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    public Object exception(BusinessException e) {
        return new Wrapper<>(e.getCode(), e.getDesc());
    }

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Object exception(Exception e) {
        log.error("ControllerAdvice", e);
        return WrapMapper.error().message(e.getClass().getName() + ": " + e.getLocalizedMessage());
    }

    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        ServletRequestAttributes servletRequestAttributes =
            (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        return request.getAttribute(ResponseResultInterceptor.RESPONSE_RESULT_ADD) instanceof ResponseResult;
    }

    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType,
                                  Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest,
                                  ServerHttpResponse serverHttpResponse) {
        return o instanceof Wrapper ? o : WrapMapper.ok().result(o);
    }
}
